﻿//结构体类型
#include<stdio.h>
#include<stddef.h>

struct Stu {
	char name[20];
	int age;
	double tall;
	double weight;
}s1;//结构体的创建，此时s1是一个全局变量
//结构体的声明

void test01() {
	struct Stu s2;//结构体的创建，s2是局部变量
}



struct Stu1 {
	char name[20];
	int age;
	double tall;
	double weight;
}* ps1,ps2;//结构体还可以直接初始化一个结构体指针变量
void test02() {
	ps1 = &ps2;//ps1是结构体指针变量，ps2是结构体变量
	int a = 0;
	int *a1=&a, b = a;
}


//结构体的自引用
struct Stu2 {
	int data;
	struct Stu2* next;
};


//匿名结构体
struct  {
	int data;
}s2,s3;
//这种结构体是一次性的，只能在全局创建变量，不能二次使用，因为该结构体没有名字



//结构体的大小
struct t1 {
	char c1;
	char c2;
	int n1;
};
struct t2 {
	char c1;
	int n1;
	char c2;
};

void test03() {
	printf("t1:c1偏移量：%zd\n", offsetof(struct t1, c1));
	printf("t1:c2偏移量：%zd\n", offsetof(struct t1, c2));
	printf("t1:n1偏移量：%zd\n", offsetof(struct t1, n1));
	printf("t1大小：%zd\n", sizeof(struct t1));
	printf("t2:c1偏移量：%zd\n", offsetof(struct t2, c1));
	printf("t2:n1偏移量：%zd\n", offsetof(struct t2, c2));
	printf("t2:c2偏移量：%zd\n", offsetof(struct t2, n1));
	printf("t2大小：%zd\n", sizeof(struct t1));
}
/*
t1:c1偏移量：0
t1:c2偏移量：1
t1:n1偏移量：4
t1大小：8
t2:c1偏移量：0
t2:n1偏移量：8
t2:c2偏移量：4
t2大小：8
 */
//结构体成员在内存中存在内存对齐现象，即结构体内存对齐
/*
* 内存对齐的规则
* 1.对齐数：vs有默认的对齐数8，但vs真正的对齐数是变量本身的大小与默认对齐数的较小值，而其他编译器的对齐数就是变量本身的大小。
* 2.偏移量：是指结构体内部变量地址相对于结构体地址的偏移量
* 3.结构体大小与根据结构体内部变量的顺序有关，第一个变量的偏移量必须为0。
* 4.变量地址的偏移量必须是其对齐数的整数倍
* 5.最终结构体的大小要满足其数值大小是最大对齐数的整数倍
* 6.如果结构体成员中也有结构体，那么这个成员结构体的对齐数就是其每个成员的对齐数的最大值
*/
//如果想要使结构体的大小尽可能小，就让小的变量尽可能聚集在一起

//结构体传参
struct t3 {
	int arr[5];
	int a;
	char c;
};
//传值调用
void printS(struct t3 tmp) {
	for (int i = 0; i < 5; i++) {
		printf("%d ", tmp.arr[i]);
	}
	printf("\n");
	printf("%d\n", tmp.a);
	printf("%c\n", tmp.c);
}
//传址调用
void printPS(struct t3* ptmp) {
	for (int i = 0; i < 5; i++) {
		printf("%d ", ptmp->arr[i]);
	}
	printf("\n");
	printf("%d\n", ptmp->a);
	printf("%c\n", ptmp->c);
}



void test04() {
	struct t3 test = { {1,2,3,4,5},3,'c' };
	printS(test);
	printPS(&test);
}
//位段
struct t4 {
	int _a : 1;
	int _b : 10;
	int _c : 5;
	int _d : 6;
};//位段里面的成员一般都是整形类型，如int,unsigned int,signed int,char等（char底层实质上也是整形）
//冒号后面的是bit位，代表所给的比特位的数量，位段的存在主要是为了节省空间，它所占的内存更小，主要应用于网络传输等。

int main() {
	test02();
	test03();
	//printf("%d",sizeof(double)); 8
	test04();
	return 0;
}